#include "dir_impl.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "file_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    dir_impl::dir_impl()
    {
    }

    dir_impl::~dir_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dir_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int dir_impl::term()
    {
        int nRet = 0;
        clear_list( m_file_list );
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dir_impl::clear_list( FILE_LIST & file_list )
    {
        int nRet = 0;

        for( FILE_ITER iter = file_list.begin(); iter != file_list.end(); ++iter )
        {
            file_impl * p = *iter;
            p->release();
        }

        file_list.clear();

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // get full file name path
    // 

    int dir_impl::get_file_path( char * lpszPath, int nLen, const char * lpszFile )
    {
        int nRet = 0;

        const char * p = 0;
        int len = 0;

        if( 0 == nRet )
        {
            if( !lpszPath || ( 0 == lstrlenA( lpszPath ) ) || !lpszFile || ( 0 == lstrlenA( lpszFile ) ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            p = StrRChrA( lpszFile, 0, '\\' );

            if( !p )
            {
                nRet = 1;
            }
            else
            {
                len = ( int )( p - lpszFile );
            }
        }

        if( 0 == nRet )
        {
            if( nLen <= len )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            lstrcpynA( lpszPath, lpszFile, len );
        }

        return nRet;
    }

    // 
    // create dir and sub dirs
    // 
    int dir_impl::create_directory( const char * lpszPath )
    {
        int nRet = 0;

        WCHAR wpath[MAX_PATH] = { 0 };
        misc_tool::utf8_to_wchar( lpszPath, -1, wpath, sizeof( wpath ), 0 );

        int nResult = SHCreateDirectoryExW( 0, wpath, 0 );

        if( ( ERROR_SUCCESS == nResult ) || ( ERROR_ALREADY_EXISTS == nResult ) )
        {
            nRet = 0;
        }

        return nRet;
    }

    // 
    // delete dir and sub dirs
    // 
    int dir_impl::delete_directory( const char * lpszPath )
    {
        int nRet = 0;

        WCHAR wpath[MAX_PATH] = { 0 };
        misc_tool::utf8_to_wchar( lpszPath, -1, wpath, sizeof( wpath ), 0 );

        HANDLE hFind = INVALID_HANDLE_VALUE;
        WIN32_FIND_DATAW fData = { 0 };
        BOOL bFind = TRUE;
        WCHAR path[4096] = { 0 };

        wcscpy_s( path, wpath );
        PathAppendW( path, L"*" );

        hFind = FindFirstFileW( path, &fData );
        bFind = INVALID_HANDLE_VALUE != hFind;

        while( bFind )
        {
            WCHAR file[4096] = { 0 };

            wcscpy_s( file, wpath );
            PathAppendW( file, fData.cFileName );

            char cfile[MAX_PATH] = { 0 };
            misc_tool::wchar_to_utf8( file, -1, cfile, sizeof( cfile ), 0 );

            if( fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                if( ( 0 != wcscmp( fData.cFileName, L"." ) ) && ( 0 != wcscmp( fData.cFileName, L".." ) ) )
                {
                    delete_directory( cfile );
                }
            }
            else
            {
                delete_file( cfile );
            }

            bFind = FindNextFileW( hFind, &fData );
        }

        RemoveDirectoryW( wpath );

        if( INVALID_HANDLE_VALUE != hFind )
        {
            FindClose( hFind );
            hFind = INVALID_HANDLE_VALUE;
        }

        return nRet;
    }

    // 
    // if a dir exists
    // 
    int dir_impl::is_dir_exist( const char * lpszPath )
    {
        int nRet = 0;

        WCHAR wpath[MAX_PATH] = { 0 };
        misc_tool::utf8_to_wchar( lpszPath, -1, wpath, sizeof( wpath ), 0 );

        HANDLE hFind = INVALID_HANDLE_VALUE;
        WIN32_FIND_DATAW fData = { 0 };

        hFind = FindFirstFileW( wpath, &fData );

        if( INVALID_HANDLE_VALUE == hFind )
        {
            nRet = 1;
        }
        else
        {
            FindClose( hFind );
            hFind = INVALID_HANDLE_VALUE;
        }

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // clear last result and find with lpszPath filter
    // 
    int dir_impl::begin_find_file( const char * lpszPath )
    {
        int nRet = 0;

        WCHAR wpath[MAX_PATH] = { 0 };
        misc_tool::utf8_to_wchar( lpszPath, -1, wpath, sizeof( wpath ), 0 );

        // 
        // clear last find result
        // 
        clear_list( m_file_list );

        // 
        // find
        // 
        HANDLE hFind = INVALID_HANDLE_VALUE;
        WIN32_FIND_DATAW fData = { 0 };
        WCHAR path[4096] = { 0 };
        BOOL bFind = TRUE;

        wcscpy_s( path, wpath );
        PathAppendW( path, L"*" );

        hFind = FindFirstFileW( path, &fData );
        bFind = INVALID_HANDLE_VALUE != hFind;

        while( bFind )
        {
            i_file::enumFileType enumType = i_file::FILE_TYPE_NONE;

            if( fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                if( ( 0 != wcscmp( fData.cFileName, L"." ) ) && ( 0 != wcscmp( fData.cFileName, L".." ) ) )
                {
                    enumType = i_file::FILE_TYPE_DIR;
                }
                else
                {
                    enumType = i_file::FILE_TYPE_NONE;
                }
            }
            else
            {
                enumType = i_file::FILE_TYPE_FILE;
            }

            if( i_file::FILE_TYPE_NONE != enumType )
            {
                file_impl * p = 0;
                
                g_pXosImpl->create( i_xos::XOS_OBJ_FILE, ( void ** )&p );

                if( p )
                {
                    misc_tool::wchar_to_utf8( fData.cFileName, -1, p->m_szFileName, sizeof( p->m_szFileName ), 0 );
                    p->m_enumType = enumType;
                    m_file_list.push_back( p );
                }
            }

            bFind = FindNextFileW( hFind, &fData );
        }

        if( INVALID_HANDLE_VALUE != hFind )
        {
            FindClose( hFind );
            hFind = INVALID_HANDLE_VALUE;
        }

        return nRet;
    }

    // 
    // finish find with filter
    // 
    int dir_impl::end_find_file()
    {
        int nRet = 0;

        // 
        // clear last find results
        // 
        clear_list( m_file_list );

        return nRet;
    }

    // 
    // get find results one by one. this will remove i_file from inner i_file list.
    // user should release i_file
    // 
    int dir_impl::get_find_result( i_file ** ppFile )
    {
        int nRet = 0;

        if( m_file_list.size() > 0 )
        {
            file_impl * p = m_file_list.front();
            m_file_list.pop_front();
            *ppFile = p;
        }
        else
        {
            *ppFile = 0;
            nRet = 1;
        }

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // if a file exists
    // 
    int dir_impl::is_file_exist( const char * lpszFileName )
    {
        int nRet = 0;

        WCHAR wfile[MAX_PATH] = { 0 };
        misc_tool::utf8_to_wchar( lpszFileName, -1, wfile, sizeof( wfile ), 0 );

        HANDLE hFile = CreateFileW( wfile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );

        if( INVALID_HANDLE_VALUE == hFile )
        {
            nRet = 1;
        }
        else
        {
            CloseHandle( hFile );
            hFile = INVALID_HANDLE_VALUE;
        }

        return nRet;
    }

    // 
    // delete a file
    // 
    int dir_impl::delete_file( const char * lpszFileName )
    {
        int nRet = 0;

        WCHAR wfile[MAX_PATH] = { 0 };
        misc_tool::utf8_to_wchar( lpszFileName, -1, wfile, sizeof( wfile ), 0 );

        if( !DeleteFileW( wfile ) )
        {
            nRet = 1;
        }

        return nRet;
    }

    // 
    // get file size
    // 
    int dir_impl::get_file_size( const char * lpszFile, xos_i64 * lpSize64 )
    {
        int nRet = 0;

        file_impl tool;

        nRet = tool.open( lpszFile, i_file::FILE_READ, i_file::SHARE_READ | i_file::SHARE_WRITE, i_file::FILE_OPEN );

        if( 0 == nRet )
        {
            nRet = tool.get_file_size( lpSize64 );
        }

        tool.close();

        return nRet;
    }

    // 
    // rename a file
    // 
    int dir_impl::rename_file( const char * lpszDesName, const char * lpszSrcName )
    {
        int nRet = 0;

        WCHAR src_file[MAX_PATH] = { 0 }, dest_file[MAX_PATH] = { 0 };

        misc_tool::utf8_to_wchar( lpszDesName, -1, src_file, sizeof( src_file ), 0 );
        misc_tool::utf8_to_wchar( lpszSrcName, -1, dest_file, sizeof( dest_file ), 0 );

        if( !MoveFileW( src_file, dest_file ) )
        {
            nRet = 1;
        }

        return nRet;
    }

    // 
    // release
    // 
    int dir_impl::release()
    {
        int nRet = 0;

        term();
        put_back_lock();

        return nRet;
    }
} // xos
